package com.yanyeori.framework.core.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 日期工具类
 *
 * @author chenkuan 2021/1/22
 */
public class DateUtil {
    /**
     * 获得当前时间的毫秒数
     */
    public static long millis() {
        return System.currentTimeMillis();
    }

    /**
     * Date格式化为字符串
     *
     * @param date      date
     * @param formatter 字符格式
     */
    public static String format(Date date, String formatter) {
        if (date == null) {
            return null;
        }
        Objects.requireNonNull(formatter, "The formatter cannot be empty");
        return DateTimeFormatter.ofPattern(formatter).format(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()));
    }

    /**
     * 毫秒时间戳格式化为字符串
     *
     * @param time      毫秒时间戳
     * @param formatter 字符格式
     */
    public static String format(long time, String formatter) {
        Objects.requireNonNull(formatter, "The formatter cannot be empty");
        return DateTimeFormatter.ofPattern(formatter).format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()));
    }

    /**
     * 字符格式自适应转为Date格式
     */
    public static Date format(String date) {
        if (date == null || date.length() == 0) {
            return null;
        }
        String pattern;
        String separator = String.valueOf(date.charAt(4));
        if (separator.matches("\\d*")) {
            separator = "";
        }
        int length = date.indexOf(" ");
        if (length == -1) {
            length = date.length();
        }
        int sepLength = separator.length() * 2;
        if (length == (8 + sepLength)) {
            pattern = "yyyy" + separator + "MM" + separator + "dd";
        } else if (length == (7 + sepLength)) {
            pattern = "yyyy" + separator + "M" + separator + "dd";
        } else if (length == (6 + sepLength)) {
            pattern = "yyyy" + separator + "M" + separator + "d";
        } else {
            pattern = "yyyyMMdd";
        }
        pattern = pattern + " HH:mm:ss.SSS";
        pattern = pattern.substring(0, Math.min(pattern.length(), date.length()));
        try {
            return new SimpleDateFormat(pattern).parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取Calendar
     */
    public static Calendar calendar() {
        return Calendar.getInstance();
    }

    /**
     * 获取指定Date的Calendar
     */
    public static Calendar calendar(Date date) {
        Calendar calendar = calendar();
        calendar.setTime(date);
        return calendar;
    }

    /**
     * Date格式化，去除时分秒毫秒：Date -> yyyyMMdd 0:0:0:0
     */
    public static Date dayOfStart(Date date) {
        if (date == null) {
            return null;
        }
        Calendar calendar = calendar(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * Date格式化，时分秒毫秒为日末：Date -> yyyyMMdd 23:59:59:999
     */
    public static Date dayOfEnd(Date date) {
        if (date == null) {
            return null;
        }
        Calendar calendar = calendar(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }

    /**
     * 获取指定天数之后的日期
     */
    public static Date addDate(Date date, int amount) {
        return add(date, Calendar.DATE, amount);
    }

    /**
     * 获取指定单位数量之后的日期
     */
    public static Date add(Date date, int field, int amount) {
        Calendar calendar = calendar(date);
        calendar.add(field, amount);
        return calendar.getTime();
    }

    /**
     * 判断是否月末日
     */
    public static boolean isEndOfMonth(Date date) {
        Calendar calendar = calendar(date);
        int monthBef = calendar.get(Calendar.MONTH);
        calendar.add(Calendar.DATE, 1);
        int monthAft = calendar.get(Calendar.MONTH);
        return monthBef != monthAft;
    }

    /**
     * 判断是否季度月
     */
    public static boolean isQuarter(Date date) {
        Calendar calendar = calendar(date);
        int month = calendar.get(Calendar.MONTH);
        return month == Calendar.MARCH || month == Calendar.JUNE || month == Calendar.SEPTEMBER || month == Calendar.DECEMBER;
    }

    /**
     * 获得当前Chinese月份
     */
    public static int month() {
        return calendar().get(Calendar.MONTH) + 1;
    }

    /**
     * 获得月份中的第几天
     */
    public static int dayOfMonth() {
        return calendar().get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 今天是星期的第几天
     */
    public static int dayOfWeek() {
        return calendar().get(Calendar.DAY_OF_WEEK);
    }

    // 今天是年中的第几天
    public static int dayOfYear() {
        return calendar().get(Calendar.DAY_OF_YEAR);
    }

    /**
     * 判断原日期是否在目标日期之前
     */
    public static boolean isBefore(Date src, Date dst) {
        return src.before(dst);
    }

    /**
     * 判断原日期是否在目标日期之后
     */
    public static boolean isAfter(Date src, Date dst) {
        return src.after(dst);
    }

    /**
     * 判断两日期是否相同
     */
    public static boolean isEqual(Date date1, Date date2) {
        return date1.compareTo(date2) == 0;
    }

    /**
     * 判断两日期（年月日）是否相同
     */
    public static boolean isEqualDate(Date date1, Date date2) {
        return isEqualDate(calendar(date1), calendar(date2));
    }

    /**
     * 判断两日期（年月日）是否相同
     */
    public static boolean isEqualDate(Calendar calendar1, Calendar calendar2) {
        return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR)
                && calendar1.get(Calendar.DAY_OF_YEAR) == calendar2.get(Calendar.DAY_OF_YEAR);
    }

    /**
     * 判断某个日期是否在某个日期范围
     */
    public static boolean between(Date date, Date beginDate, Date endDate) {
        return beginDate.before(date) && endDate.after(date);
    }

    /**
     * 获得当前月的第一天 HH:mm:ss SS为零
     */
    public static Date firstDayOfMonth() {
        Calendar cal = calendar();
        cal.set(Calendar.DAY_OF_MONTH, 1); // M月置1
        cal.set(Calendar.HOUR_OF_DAY, 0);// H置零
        cal.set(Calendar.MINUTE, 0);// m置零
        cal.set(Calendar.SECOND, 0);// s置零
        cal.set(Calendar.MILLISECOND, 0);// S置零
        return cal.getTime();
    }

    /**
     * 获得当前月的最后一天 HH:mm:ss为0，毫秒为999
     */
    public static Date lastDayOfMonth() {
        Calendar cal = calendar();
        cal.set(Calendar.DAY_OF_MONTH, 0); // M月置零
        cal.set(Calendar.HOUR_OF_DAY, 0); // H置零
        cal.set(Calendar.MINUTE, 0); // m置零
        cal.set(Calendar.SECOND, 0); // s置零
        cal.set(Calendar.MILLISECOND, 0); // S置零
        cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) + 1); // 月份+1
        cal.set(Calendar.MILLISECOND, -1); // 毫秒-1
        return cal.getTime();
    }

    /**
     * 获取两个日期之间相差天数，首尾只算一天
     *
     * @param date1 yyyyMMdd
     * @param date2 yyyyMMdd
     * @return 天数差
     */
    public static int getDayBetween(String date1, String date2) {
        Objects.requireNonNull(date1, "date1 not be null");
        Objects.requireNonNull(date2, "date2 not be null");
        return getDayBetween(format(date1), format(date2));
    }

    /**
     * 获取两个日期之间相差天数，首尾只算一天
     *
     * @param date1 Date
     * @param date2 Date
     * @return 天数差
     */
    public static int getDayBetween(Date date1, Date date2) {
        Objects.requireNonNull(date1, "The date1 cannot be empty");
        Objects.requireNonNull(date2, "The date2 cannot be empty");
        long millStart = dayOfStart(date1).getTime();
        long millEnd = dayOfStart(date2).getTime();
        long daysBetween = (millEnd - millStart) / (TimeUnit.DAYS.toMillis(1));
        return Integer.parseInt(String.valueOf(daysBetween));
    }
}
